home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / calc.arc / CALC.C next >
C/C++ Source or Header  |  1985-11-24  |  19KB  |  602 lines

  1. /* 
  2. *  CALC.C
  3. *  
  4. *  Author:  R. E. Sawyer
  5. *  Date:  16 Nov 85
  6. *
  7. *  Language:  C (DeSmet V2.4)
  8. *
  9. *  Description:  CALC is an interactive RPN-style calculator.  Each line of
  10. *                instructions entered at the keyboard is immediately interp-
  11. *                reted, and CALC may also be directed to save each line in a 
  12. *                journal file for later re-play. Such a file may also be
  13. *                created by previous use of a text editor.
  14. */
  15.  
  16. #include <math.h>
  17. #include <stdio.h>
  18.  
  19. #define MAXLINE    80
  20. #define MAXWORD    20
  21. #define MAXSTACK   100
  22. #define MAXMEM     100
  23. #define MAXKEY     100
  24. #define MAXVAR     100
  25. #define MAXVLEN    6
  26. #define TAB        "        "
  27.  
  28. FILE *fin = 0;
  29. FILE *fout = 0;
  30. int isfromfile = 0;
  31. int istofile = 0;
  32.  
  33. static char vname[MAXVAR][MAXVLEN] = {"\0"};
  34. static double val[MAXVAR] = {0.0};
  35. int vnum = 0;
  36.  
  37. int sp = 0;
  38. double stack[MAXSTACK+1];
  39. double mem[MAXMEM+1];
  40. extern double atof();
  41.  
  42. static char *keyword[] = {
  43.                          "HELP  display this summary",
  44.                          "QUIT  exit CALC",
  45.                          "nnn   append s0 = any number nnn",
  46.                          "abc   append s0 = value of variable abc",
  47.                          "=abc  store s0 as variable abc, delete s0",
  48.                          "=     display s0",
  49.                          "+     s0 <-- s1 + s0, delete s1",
  50.                          "-     s0 <-- s1 - s0, delete s1",
  51.                          "*     s0 <-- s1 * s0, delete s1",
  52.                          "/     s0 <-- s1 / s0, delete s1",
  53.                          "^     s0 <-- s1 to the power s0, delete s1",
  54.                          "?<    s0 <-- 1(0) if s1 < (>=) s0, delete s1",
  55.                          "?<=   s0 <-- 1(0) if s1 <= (>) s0, delete s1",
  56.                          "?=    s0 <-- 1(0) if s1 = (<>) s0, delete s1",
  57.                          "ABS   s0 <-- absolute value of s0",
  58.                          "ACOS  s0 <-- arccosine of s0",
  59.                          "ASIN  s0 <-- arcsine of s0",
  60.                          "ATAN  s0 <-- arctangent of s0",
  61.                          "CEIL  s0 <-- least integer not less than s0",
  62.                          "CHS   s0 <-- -s0",
  63.                          "COS   s0 <-- cosine of s0",
  64.                          "COSH  s0 <-- hyperbolic cosine of s0",
  65.                          "EXP   s0 <-- e to the power s0",
  66.                          "EXP10 s0 <-- 10 to the power s0",
  67.                          "FLOOR s0 <-- greatest integer not greater than s0",
  68.                          "INV   s0 <-- 1 / s0",
  69.                          "LOG   s0 <-- base e logarithm of s0",
  70.                          "LOG10 s0 <-- base 10 logarithm of s0",
  71.                          "MAX   s0 <-- maximum of s0 & s1, delete s1",
  72.                          "MIN   s0 <-- minimum of s0 & s1, delete s1",
  73.                          "MOD   s0 <-- s1 modulo s0, delete s1",
  74.                          "PSE   pause until any key is typed (and ignored)",
  75.                          "PI    append s0 = 3.14159...",
  76.                          "SIN   s0 <-- sine of s0",
  77.                          "SINH  s0 <-- hyperbolic sine of s0",
  78.                          "SQR   s0 <-- s0 * s0",
  79.                          "SQRT  s0 <-- square root of s0",
  80.                          "TAN   s0 <-- tangent of s0",
  81.                          "TANH  s0 <-- hyperbolic tangent of s0",
  82.                          "CL0   delete s0",
  83.                          "CLA   delete stack & variables, zero all registers",
  84.                          "CLM   zero all registers",
  85.                          "CLS   delete stack",
  86.                          "CLV   delete all variables",
  87.                          "RCL   append s0 = register s0",
  88.                          "SHO   display stack",
  89.                          "XCH   exchange s0,s1",
  90.                          "STO   store s1 in register s0, delete s0",
  91.                          "STO+  add s1 to register s0, delete s0",
  92.                          "STO-  subtract s1 from register s0, delete s0",
  93.                          "STO*  multiply register s0 by s1, delete s0",
  94.                          "STO/  divide register s0 by s1, delete s0",
  95.                          "<<abc  execute instructions in file abc",
  96.                          ">>abc  begin saving instructions to file abc",
  97.                          ">>     stop saving instructions to file"
  98.                          };
  99.  
  100. main()
  101.     {
  102.     int i, j;
  103.     char line[MAXLINE+1];
  104.     char word[MAXWORD+1];
  105.     int start;
  106.     int iop1;
  107.     double op1, op2;
  108.     double push(), pop();
  109.     FILE *opener();
  110.  
  111.     header();
  112.     while (TRUE)
  113.         {
  114.         start = 0;
  115.         if (!isfromfile)
  116.             printf("CALC> ");
  117.         getline(line);
  118.         if (istofile && !(line[0] == '>' && line[1] == '>'))
  119.             {
  120.             fputs(line,fout);
  121.             fputs("\n",fout);
  122.             }
  123.         if (isfromfile)
  124.             printf("%s",line);
  125.         while (getword(word, line, &start))
  126.             {
  127.             if (word[0] == '<' && word[1] == '<')
  128.                 {
  129.                 fin = opener(word+2,0);
  130.                 isfromfile = fin;
  131.                 break;
  132.                 }
  133.             if (word[0] == '>' && word[1] == '>')
  134.                 {
  135.                 if (istofile)
  136.                    {
  137.                    fclose(fout);
  138.                    istofile = 0;
  139.                    }
  140.                 else if (!isfromfile)
  141.                    {
  142.                    fout = opener(word+2,1);
  143.                    istofile = fout;                    
  144.                    break;
  145.                    }
  146.                 }
  147.             else if (word[0] == '=' && isalpha(word[1]))
  148.                 if (sp > 0)
  149.                     if ( (i=search(vname,word+1)) >= 0 )
  150.                         val[i] = pop();
  151.                     else
  152.                         if (vnum <= MAXVAR)
  153.                             {
  154.                             strcpy(vname+vnum, word+1);
  155.                             val[vnum] = pop();
  156.                             ++vnum;
  157.                             }
  158.                         else
  159.                             printf("%sNo room for %s.\n",TAB,word+1);
  160.                 else
  161.                     printf("%sNothing to store in %s.\n",TAB,word+1);
  162.             else if (isdigit(word[0]) || word[0] == '.')
  163.                 push(atof(word));
  164.             else if (word[0] == '-' && (isdigit(word[1]) || word[1] == '.'))
  165.                 push(-atof(word+1));
  166.             else if (is(word,"CL0"))
  167.                 if (sp > 0)
  168.                     pop();
  169.                 else
  170.                     printf("%sNothing to clear.\n",TAB);
  171.             else if (is(word,"STO"))
  172.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  173.                     mem[iop1] = push(pop());
  174.                 else
  175.                     {
  176.                     printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
  177.                     break;
  178.                     }
  179.             else if (is(word,"STO+"))
  180.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  181.                     mem[iop1] += push(pop());
  182.                 else
  183.                     {
  184.                     printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
  185.                     break;
  186.                     }
  187.             else if (is(word,"STO-"))
  188.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  189.                     mem[iop1] -= push(pop());
  190.                 else
  191.                     {
  192.                     printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
  193.                     break;
  194.                     }
  195.             else if (is(word,"STO*"))
  196.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  197.                     mem[iop1] *= push(pop());
  198.                 else
  199.                     {
  200.                     printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
  201.                     break;
  202.                     }
  203.             else if (is(word,"STO/"))
  204.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  205.                     mem[iop1] /= push(pop());
  206.                 else
  207.                     {
  208.                     printf("%sMust have 0<=M<=%3.0d in M STO.\n",TAB,MAXMEM);
  209.                     break;
  210.                     }
  211.             else if (is(word,"RCL"))
  212.                 if ((iop1 = (int)pop()) <= MAXMEM && iop1 >= 0)
  213.                     push(mem[iop1]);
  214.                 else
  215.                     {
  216.                     printf("%sMust have 0<=M<=%3.0d in M RCL.\n",TAB,MAXMEM);
  217.                     break;
  218.                     }
  219.             else if (is(word,"+"))
  220.                 push(pop() + pop());
  221.             else if (is(word,"*"))
  222.                 push(pop() * pop());
  223.             else if (is(word,"-"))
  224.                 {
  225.                 op2 = pop();
  226.                 push(pop() - op2);
  227.                 }
  228.             else if (is(word,"/"))
  229.                 {
  230.                 op2 = pop();
  231.                 if (op2 != 0.0)
  232.                     push(pop() / op2);
  233.                 else
  234.                     {
  235.                     printf("%sAttempted division by zero.\n",TAB);
  236.                     break;
  237.                     }
  238.                 }
  239.             else if (is(word,"?<"))
  240.                 {
  241.                 op2 = pop();
  242.                 push(pop() < op2 ? 1.0 : 0.0);
  243.                 }
  244.             else if (is(word,"?<="))
  245.                 {
  246.                 op2 = pop();
  247.                 push(pop() <= op2 ? 1.0 : 0.0);
  248.                 }
  249.             else if (is(word,"?="))
  250.                 {
  251.                 op2 = pop();
  252.                 push(pop() == op2 ? 1.0 : 0.0);
  253.                 }
  254.             else if (is(word,"CHS"))
  255.                 push(-pop());
  256.             else if (is(word,"XCH"))
  257.                 {
  258.                 op1 = pop();
  259.                 op2 = pop();
  260.                 push(op1);
  261.                 push(op2);
  262.                 }
  263.             else if (is(word,"INV"))
  264.                 if ((op1=pop()) != 0.0)
  265.                     push(1.0 / pop());
  266.                 else
  267.                     {
  268.                     printf("%sMust have X<>0 in 1/X.\n",TAB);
  269.                     break;
  270.                     }
  271.             else if (is(word,"ABS"))
  272.                 push(fabs(pop()));
  273.             else if (is(word,"ACOS"))
  274.                 push(acos(pop()));
  275.             else if (is(word,"ASIN"))
  276.                 push(asin(pop()));
  277.             else if (is(word,"ATAN"))
  278.                 push(atan(pop()));
  279.             else if (is(word,"CEIL"))
  280.                 push(ceil(pop()));
  281.             else if (is(word,"COS"))
  282.                 push(cos(pop()));
  283.             else if (is(word,"EXP"))
  284.                 push(exp(pop()));
  285.             else if (is(word,"EXP10"))
  286.                 push(exp10(pop()));
  287.             else if (is(word,"FLOOR"))
  288.                 push(floor(pop()));
  289.             else if (is(word,"LOG"))
  290.                 if ((op1=pop()) > 0.0)
  291.                     push(log(op1));
  292.                 else
  293.                     {
  294.                     printf("%sMust have X>0 in LOG(X).\n",TAB);
  295.                     break;
  296.                     }
  297.             else if (is(word,"LOG10"))
  298.                 if ((op1=pop()) > 0.0)
  299.                     push(log10(op1));
  300.                 else
  301.                     {
  302.                     printf("%sMust have X>0 LOG10(X).\n",TAB);
  303.                     break;
  304.                     }
  305.             else if (is(word,"^"))
  306.                 if ((op2 = pop()) > 0.0)
  307.                     push(pow(pop(), op2));
  308.                 else
  309.                     {
  310.                     printf("%sMust have X>0 in X^Y.\n", TAB);
  311.                     break;
  312.                     }
  313.             else if (is(word,"SIN"))
  314.                 push(sin(pop()));
  315.             else if (is(word,"SQR"))
  316.                 push((op1=pop()) * op1);
  317.             else if (is(word,"SQRT"))
  318.                 if ((op1=pop()) >= 0.0)
  319.                     push(sqrt(op1));
  320.                 else
  321.                     {
  322.                     printf("%sMust have X>=0 in SQRT(X).\n",TAB);
  323.                     break;
  324.                     }
  325.             else if (is(word,"TAN"))
  326.                 push(tan(pop()));
  327.             else if (is(word,"MIN"))
  328.                 {
  329.                 op2 = pop();
  330.                 push(((op1 = pop()) < op2) ? op1 : op2);
  331.                 }
  332.             else if (is(word,"MAX"))
  333.                 {
  334.                 op2 = pop();
  335.                 push(((op1 = pop()) > op2) ? op1 : op2);
  336.                 }
  337.             else if (is(word,"SINH"))
  338.                 push(0.5*(exp(op1=pop()) - exp(-op1)));
  339.             else if (is(word,"COSH"))
  340.                 push(0.5*(exp(op1=pop()) + exp(-op1)));
  341.             else if (is(word,"TANH"))
  342.                 {
  343.                 op2 = exp(op1=pop()) - exp(-op1);
  344.                 push(op2 / (exp(op1) + exp(-op1)));
  345.                 }
  346.             else if (is(word,"PI"))
  347.                 push(4.0*atan(1.0));
  348.             else if (is(word,"="))
  349.                 if (sp > 0)
  350.                     printf("%s%20.14le\n", TAB, push(pop()));
  351.                 else
  352.                     printf("%sStack empty.\n",TAB);
  353.             else if (is(word,"CLS"))
  354.                 clearstack();
  355.             else if (is(word,"CLM"))
  356.                 clearmem();
  357.             else if (is(word,"CLV"))
  358.                 clearvar();
  359.             else if (is(word,"CLA"))
  360.                 {
  361.                 clearstack();
  362.                 clearmem();
  363.                 clearvar();
  364.                 }
  365.             else if (is(word,"SHO"))
  366.                 showstack();
  367.             else if (is(word,"HELP"))
  368.                 help();
  369.             else if (is(word,"QUIT"))
  370.                 exit();
  371.             else if ( (i=search(vname,word)) >= 0 )
  372.                 push(val[i]);
  373.             else if (is(word,"PSE"))
  374.                 {
  375.                 getchar();
  376.                 putchar('\b\n');
  377.                 }
  378.             else 
  379.                 {
  380.                 printf("%sUnrecognized symbol:  %s\n", TAB, word);
  381.                 printf("%sDo you want help? (y/n) ",TAB);
  382.                 if (tolower(getchar()) == 'y')
  383.                     help();
  384.                 else
  385.                     printf("\n");
  386.                 }
  387.             }
  388.         }
  389.     }
  390.  
  391.  
  392. double push(x)
  393.     double x;
  394.     {
  395.     if (sp < MAXSTACK)
  396.         {
  397.         stack[sp++] = x;
  398.         }
  399.     else
  400.         {
  401.         printf("%sStack overflow.\n", TAB);
  402.         clearstack();
  403.         }
  404.     return (x);
  405.     }
  406.  
  407.  
  408. double pop()
  409.     {
  410.     double x;
  411.  
  412.     if (sp > 0)
  413.         x = stack[--sp];
  414.     else
  415.         {
  416.         printf("%sValue not found -- stack may be corrupted.\n", TAB);
  417.         clearstack();
  418.         x = 0.0;
  419.         }
  420.     return (x);
  421.     }
  422.  
  423.  
  424. void clearstack()
  425.    {
  426.    sp = 0;
  427.    }
  428.         
  429.  
  430. void showstack()
  431.     {
  432.     int i;
  433.     if (sp == 0)
  434.         {
  435.         printf("%sStack empty.\n", TAB);
  436.         return;
  437.         }
  438.     for (i=0; i<sp-1; ++i)
  439.         printf("%s%20.14le\n", TAB, stack[i]);
  440.     printf("%s%20.14le <--TOP\n", TAB, stack[sp-1]);
  441.     }
  442.  
  443.  
  444. void clearmem()
  445.     {
  446.     int i;
  447.  
  448.     for (i=0; i<=MAXMEM; ++i)
  449.         mem[i] = 0;
  450.     }
  451.  
  452.  
  453. void clearvar()
  454.     {
  455.     vnum = 0;
  456.     vname[0][0] = '\0';
  457.     }
  458.  
  459.  
  460. void help()
  461.     {
  462.     int i;
  463.  
  464.     printf("\n\n\n\n\n\n");
  465.     printf("%sCALC is an interactive RPN-style calculator with an \n",TAB);
  466.     printf("%sinstruction set resembling that of an HP calculator.\n",TAB);
  467.     printf("%sEach line of instructions entered at the keyboard is\n",TAB);
  468.     printf("%simmediately executed, and may also be automatically \n",TAB);
  469.     printf("%sjournaled in a command file.  CALC can be made to read\n",TAB);
  470.     printf("%sand execute the instructions on-file at any time.  A\n",TAB);
  471.     printf("%scommand file can also be created with a text editor.\n",TAB);
  472.     printf("\n%sAs in an HP calulator, instructions are interpreted\n",TAB);
  473.     printf("%sas \"Reverse Polish Notation\", and operate on values\n",TAB);
  474.     printf("%sstored on a \"stack\" -- a \"last-in first-out\" list.\n",TAB);
  475.     printf("%sThe stack is represented as (...,s2,s1,s0), where s0\n",TAB);
  476.     printf("%sis accessed first (\"top-of-stack\"), s1 is next, etc.\n",TAB);
  477.     printf("%sAll values are double precision (8-byte) floats.\n\n",TAB);
  478.     printf("%sThe following are valid symbols if separated by spaces:\n",TAB);
  479.     printf("\n\n\n\n\n\n");
  480.     more();
  481.     for (i=0; i<MAXKEY && *keyword[i] != '\0'; ++i)
  482.         {
  483.         if (i%24 == 0 && i>0)
  484.             more();
  485.         printf("%s%s\n",TAB,keyword[i]);
  486.         }
  487.     printf("\n\n");
  488.     }
  489.  
  490. more()
  491.     {
  492.     printf("-MORE-");
  493.     getchar();
  494.     printf("\b\b\b\b\b\b\b");
  495.     }
  496.  
  497. static char *q[3] = {"r","w","a"};
  498.  
  499. FILE *opener(s,t)
  500.     char *s;
  501.     int t;
  502.     {
  503.     FILE *f;
  504.  
  505.     if ((f = fopen(s,q[t])) == NULL)
  506.         printf("%sCan't open %s.\n",TAB,s);
  507.     return (f);
  508.     }
  509.  
  510.  
  511. /* get a line of text, from the keyboard or a file, to line[] string*/
  512. int getline(line)
  513.     char line[];
  514.     {
  515.     if (isfromfile)
  516.         {
  517.         if (fgets(line,MAXLINE,fin) == NULL)
  518.             {
  519.             fclose(fin);
  520.             isfromfile = 0;
  521.             }
  522.         }
  523.     else
  524.         gets(line);
  525.     }
  526.  
  527. /* get word-string from line-string beginning at index=start */
  528. /* return length of word-string */
  529.  
  530. int getword(word, line, start)
  531.     char word[];
  532.     char line[];
  533.     int *start;
  534.     {
  535.     int i, j;
  536.  
  537.     for (i=*start, j=0; line[i] != '\0'; ++i)
  538.         {
  539.         if (!isop(line[i]))
  540.             ;
  541.         else
  542.             {
  543.             for (j=0; j <= MAXWORD && isop(line[i]); ++j)
  544.                 word[j] = toupper(line[i++]);
  545.             word[j] = '\0';
  546.             *start = i;
  547.             break;
  548.             }
  549.         }
  550.     if (j == 0)
  551.         word[0] = '\0';
  552.     if (j > MAXWORD)
  553.         {
  554.         printf("%sSymbol too long:  %s", TAB, word);
  555.         for (i=*start; i<=MAXLINE && isop(line[i]); ++i)
  556.             printf("%c", toupper(line[i]));
  557.         printf("\n");
  558.         }
  559.     return (j);
  560.     } 
  561.  
  562.  
  563. /* return TRUE if c is in the alphabet for words */
  564.  
  565. int isop(c)
  566.     char c;
  567.     {
  568.     int i;
  569.  
  570.     if (c >= '!' && c <= '~')
  571.         return (TRUE);
  572.     else
  573.         return (FALSE);
  574.     }    
  575.  
  576.  
  577. int is(word, str)
  578.     char word[];
  579.     char str[];
  580.     {
  581.     return (strcmp(word, str) == 0);
  582.     }
  583.  
  584.  
  585. int search(var, word)
  586.     char var[][MAXVLEN];
  587.     char word[];
  588.     {
  589.     int i;
  590.  
  591.     for (i=0; i <= MAXVAR && (var[i][0] != '\0'); ++i)
  592.         if (is(word,var[i]))
  593.             return (i);
  594.     return (-1);
  595.     }
  596.  
  597. void header()
  598.     {
  599.     printf("\nCALC  --  R. E. Sawyer, 16 Nov 85\n\n");
  600.     }
  601.